-
Notifications
You must be signed in to change notification settings - Fork 121
Customer Search: Implement UI #7880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
You can test the changes from this Pull Request by:
|
| final class CustomerSearchUICommand: SearchUICommand { | ||
|
|
||
| typealias Model = Customer | ||
| typealias CellViewModel = TitleAndSubtitleAndStatusTableViewCell.ViewModel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy to get a different recommendation for the CellView we want to use here, at the moment I'm using TitleAndSubtitleAndStatusTableViewCell just for convenience, as must conform to SearchResultCell there are several options to choose from without having to create a new one (or I could create a new one as well!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that you're going to have the avatar in there too, you might want to try adding SearchResultCell conformance to LeftImageTitleSubtitleTableViewCell?
The only thing it won't do is any attributed text in the subtitle for an underlined email as on Android... but I don't personally think that should be a blocker.
|
@rachelmcr @ThomazFB @Ecarrion please leave a comment if any of you plan to review the PR today, otherwise I'll review it with @joshheald during our pairing session. Thanks! |
| } | ||
|
|
||
| func searchResultsPredicate(keyword: String) -> NSPredicate? { | ||
| return NSPredicate(format: "ANY searchResults.keyword = %@", keyword) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs to add siteID! We'll add it in a future PR/commit as this is currently behind a feature flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep! Don't forget both places, this is the one for the CustomerSearchResults rather than the Customer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely, I went ahead and changed it in this PR as was a quick one: a8dd778
joshheald
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done. I was able to test it and get some search results showing in the app.
The comments here can all be addressed in a future PR, nothing is blocking.
Other general things I noticed, outside the scope of this PR, for your notes:
- There are lots of network requests to
/wc/v3/customers/0, which will always fail, these could be filtered out. - There's no empty state yet, just a blank white screen.
- The search doesn't behave the same as on Android. On Android, search looks at the email field only, and on iOS, it looks at the name fields only. Apologies if I'm forgetting some context here, if Android are going to change that...
![]()
| final class CustomerSearchUICommand: SearchUICommand { | ||
|
|
||
| typealias Model = Customer | ||
| typealias CellViewModel = TitleAndSubtitleAndStatusTableViewCell.ViewModel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that you're going to have the avatar in there too, you might want to try adding SearchResultCell conformance to LeftImageTitleSubtitleTableViewCell?
The only thing it won't do is any attributed text in the subtitle for an underlined email as on Android... but I don't personally think that should be a blocker.
| 4598298028574688003A9AFE /* Inject */ = { | ||
| isa = XCSwiftPackageProductDependency; | ||
| package = 4598297F28574688003A9AFE /* XCRemoteSwiftPackageReference "Inject.git" */; | ||
| package = 4598297F28574688003A9AFE /* XCRemoteSwiftPackageReference "Inject" */; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has Inject changed for any particular reason? What happens if you revert these changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! And that's a good question:
The only difference I'm seeing is that when I revert the changes is that I can see the iOS 15.0 minimum support warnings for YosemiteTests related to kUTTypeJPEG deprecation.
This most likely comes from me switching to iOS15 temporarily when working on this, as at the same time we were upgrading the app minimum version for the app and I wanted to see if my changes came with potential deprecations. Then when I switched back to iOS14, I may have missed the changes in project.pbxproj.
I see these changes are part of trunk already, but I reverted here: da5e401 as this change shouldn't go with my PR anyway 👍
| func createResultsController() -> ResultsController<StorageCustomer> { | ||
| let storageManager = ServiceLocator.storageManager | ||
| let descriptor = NSSortDescriptor(keyPath: \StorageCustomer.customerID, ascending: false) | ||
| return ResultsController<StorageCustomer>(storageManager: storageManager, sortedBy: [descriptor]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will display StorageCustomers from Core Data for any site, not just the current one, which could lead to confusion for some merchants with multiple stores.
If you add a predicate specifying the siteID, that should resolve the issue. No need to block this PR since it's behind a feature flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I committed the changes a8dd778 with this one as we went through these in our pairing as was pretty quick 👍
| func createCellViewModel(model: Customer) -> TitleAndSubtitleAndStatusTableViewCell.ViewModel { | ||
| return CellViewModel( | ||
| id: "\(model.customerID)", | ||
| title: "\(model.firstName ?? "") \(model.lastName ?? "")", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This... might be the right thing to do given our data source, but names are complicated, and simply concatenating them isn't correct in all locales.
See PersonNameComponentsFormatter docs for more info. There's not necessarily anything to do here (as I don't know whether we have enough in our data source to correctly make a formatter) but I thought it would be useful for you to know about if you don't already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the link, I definitely didn't know about PersonNameComponentsFormatter. I agree with you, concatenating strings doesn't look good to me either and I'll look for cleaner alternatives (if possible). I'll dig into this document and make any necessary improvements on another PR.
| id: "\(model.customerID)", | ||
| title: "\(model.firstName ?? "") \(model.lastName ?? "")", | ||
| subtitle: model.email, | ||
| accessibilityLabel: "", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accessibility Label is required here... see what it does in VoiceOver without it: it just announces:
Button
Without any detail about the name of the user or anything else about the search result.
If you're moving to another cell, you may not have to do anything, usually we get VoiceOver in cells for free, but in this case we are specific about what the label should be in the view model.
| } | ||
|
|
||
| func searchResultsPredicate(keyword: String) -> NSPredicate? { | ||
| return NSPredicate(format: "ANY searchResults.keyword = %@", keyword) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep! Don't forget both places, this is the one for the CustomerSearchResults rather than the Customer
| var searchBarAccessibilityIdentifier: String = "customer-search-screen-search-field" | ||
|
|
||
| var cancelButtonAccessibilityIdentifier: String = "customer-search-screen-cancel-button" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably only need to set accessibilityIdentifiers if you're actually using the search in a UI test. Identifiers are nothing to do with VoiceOver and other assistive tech, in practice, they are only used for UI tests.
AccessibilityLabels are for VoiceOver and important to have on custom controls or complex groups.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL!
|
General observation: from my test site, the feature feels a bit... frustrating, in terms of the search results it can actually return. This is just a limitation of the API AFAIK, but I have lots of customer details on different orders, where the customers checked out as guests. In the Analytics section of wc-admin, it manages to link things together for those customers, even though they're guests... it certainly would be good if we could do a bit more like that for filling address details! The brief here is to get to parity with Android, but if you do have thoughts or findings which could feed in to an iteration 2 of the feature, it would be good to hear them... |
Yes, this was one of the API limitations when taking this approach (pe5pgL-3r-p2)
I believe that, depending on when we plan to change the API behaviour, we could use this to our advantage and create some sort of "advanced search" with |
Part of #7741
Branched from #7848 , that PR needs to be merged first.
Description
This PR implements the basic UI for searching Customers. The scope of this PR is limited to display a search view when we tap on the search icon, display Customer results matching our keyword, and pass the Customer data back to our
EditOrderAddressFormview when we tap in any of the Customers. Filling the data to corresponding fields will be done in a future PR.Changes
OrderCustomerListView, which is a SwiftUI wrapper for the existingSearchViewController.CustomerSearchUICommandclass, which is the implementation of the existingSearchUICommandfor Customer search.Testing instructions
EditOrderAddressForm, which we'll use to fill the Order with Customer details in a future PR.